package com.mbrs.service;

import com.mbrs.aggr.*;
import com.mbrs.repo.*;
import dml.common.id.aggr.LongIdGenerator;
import dml.common.id.aggr.UUIDIdGenerator;
import dml.common.times.KeepAlive;
import dml.users.proc.KeepAliveSessionProcesses;
import dml.users.proc.ThirdPartyloginProcesses;
import dml.users.proc.UserBanProcesses;
import dml.users.repo.*;
import erp.annotation.Process;
import erp.mongodb.MongodbRepository;
import erp.redis.RedisRepository;
import erp.repository.factory.RepositoryFactory;
import erp.viewcached.ViewCachedRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class LoginService {

    private ThirdPartyloginProcesses thirdPartyloginProcesses;

    private UserBanProcesses userBanProcesses;

    private KeepAliveSessionProcesses sessionProcesses;

    private MyUserInfoRepository myUserInfoRepository;

    private MySessionRepository mySessionRepository;

    @Autowired
    public LoginService(MongoTemplate mongoTemplate, RedisTemplate redisTemplate) {
        mySessionRepository = new RedisMySessionRepository(redisTemplate);
        UserLoginStateRepository<MyUserLoginState, Long> userLoginStateRepository =
                RepositoryFactory.newInstance(UserLoginStateRepository.class,
                        new RedisRepository<MyUserLoginState, Long>(redisTemplate, MyUserLoginState.class));
        UuidUserBindFactoryRepository myUuidUserBindFactoryRepository = new MyUuidUserBindFactoryRepository();
        myUuidUserBindFactoryRepository.put(new MyUuidUserBindFactory());

        UuidUserBindRepository<?> myUuidUserBindRepository =
                RepositoryFactory.newInstance(UuidUserBindRepository.class,
                        new MongodbRepository<MyUuidUserBind, String>(mongoTemplate, MyUuidUserBind.class));
        MyUserRepository myUserRepository = new MyUserRepository(mongoTemplate);
        SessionIdGeneratorRepository uuidSessionIdGeneratorRepository = new MySessionIdGeneratorRepository();
        uuidSessionIdGeneratorRepository.put(new UUIDIdGenerator());
        Long maxUid = myUserRepository.findMaxUserId();
        if (maxUid == null) {
            maxUid = 0L;
        }
        UserIdGeneratorRepository longUserIdGeneratorRepository = new MyUserIdGeneratorRepository();
        longUserIdGeneratorRepository.put(new LongIdGenerator(maxUid + 1));
        UserBanRepository<?, ?> myUserBanRepository =
                RepositoryFactory.newInstance(UserBanRepository.class,
                        new MongodbRepository<MyUserBan, Long>(mongoTemplate, MyUserBan.class));
        UserFactoryRepository myUserFactoryRepository = new MyUserFactoryRepository();
        myUserFactoryRepository.put(new MyUserFactory());
        SessionFactoryRepository mySessionFactoryRepository = new MySessionFactoryRepository();
        mySessionFactoryRepository.put(new MySessionFactory());
        UserLoginStateFactoryRepository userLoginStateFactoryRepository = new MyUserLoginStateFactoryRepository();
        userLoginStateFactoryRepository.put(new MyUserLoginStateFactory());
        UserBanFactoryRepository myUserBanFactoryRepository = new MyUserBanFactoryRepository();
        myUserBanFactoryRepository.put(new MyUserBanFactory());

        thirdPartyloginProcesses = new ThirdPartyloginProcesses(
                myUuidUserBindFactoryRepository, myUuidUserBindRepository,
                myUserFactoryRepository, longUserIdGeneratorRepository,
                myUserRepository, uuidSessionIdGeneratorRepository,
                mySessionFactoryRepository, mySessionRepository,
                userLoginStateRepository, userLoginStateFactoryRepository);
        userBanProcesses = new UserBanProcesses(myUserBanRepository,
                userLoginStateRepository, mySessionRepository,
                myUserBanFactoryRepository);
        sessionProcesses = new KeepAliveSessionProcesses(mySessionRepository,
                userLoginStateRepository);
        myUserInfoRepository =
                RepositoryFactory.newInstance(MyUserInfoRepository.class,
                        new ViewCachedRepository<MyUserInfo, Long>(
                                new MongodbRepository(mongoTemplate, MyUserInfo.class)));
    }

    @Process
    public PairProcessResult<MyUserBan, LoginOrRegisterResult> loginOrRegister(
            String cmgePlayerId, long currTime) {
        LoginOrRegisterResult rslt = new LoginOrRegisterResult(thirdPartyloginProcesses
                .loginOrRegister(cmgePlayerId, null, null,
                        new MySessionProperties(new KeepAlive(currTime,
                                60 * 60 * 1000)), null));
        MyUserBan ban = userBanProcesses.checkBanAndTryToReleaseUserOrLogout(
                rslt.getUser().getId(), currTime);
        return PairProcessResult.instance(ban, rslt);
    }

    @Process
    public MyUserInfo saveUserInfo(long userId, String gameUID,
                                   String channelUID, String cmgePlayerId, String channelUserId,
                                   String platformID, long loginTime, String extend, String wxSceneID,
                                   String shareMemberId, String channel) {
        MyUserInfo myUserInfo = new MyUserInfo(userId, gameUID, channelUID,
                cmgePlayerId, channelUserId, platformID, loginTime, extend,
                wxSceneID, shareMemberId, channel);
        myUserInfoRepository.put(myUserInfo);
        return myUserInfo;
    }

    @Process
    public MyUserBan ban(long userId, long liftTime, String banTip,
                         String banReason) {
        return userBanProcesses.banUser(userId, System.currentTimeMillis(),
                liftTime, new MyUserBanProperties(banTip, banReason));
    }

    @Process
    public MyUserBan liftBan(long userId) {
        return userBanProcesses.liftUserBan(userId, System.currentTimeMillis());
    }

    @Process
    public MySession checkAndRemoveOvertimeSession(String sid,
                                                   long currentTimeMillis) {
        return sessionProcesses.checkAndRemoveOvertimeSession(sid,
                currentTimeMillis);
    }

    public List<String> queryAllSessionIds() {
        return mySessionRepository.getAllSessionIds();
    }

    @Process
    public void setUserInfoExtend(long userId, String extend) {
        MyUserInfo userInfo = myUserInfoRepository.take(userId);
        userInfo.setExtend(extend);
    }

    public MyUserInfo getUserInfo(long userId) {
        return myUserInfoRepository.find(userId);
    }
}
